﻿using System;
using System.Linq;
using Belphegor.Composites;
using Belphegor.Dynamics;
using Belphegor.Helpers;
using Zeta;
using Zeta.Common.Helpers;
using Zeta.CommonBot;
using Zeta.Internals.Actors;
using Zeta.TreeSharp;
using Action = Zeta.TreeSharp.Action;

namespace Belphegor.Routines
{
    public class DemonHunter
    {
        static DemonHunter()
        {
            GameEvents.OnGameLeft += OnGameLeft;
            GameEvents.OnPlayerDied += OnGameLeft;
        }

        private static WaitTimer _markTimer = new WaitTimer(TimeSpan.FromSeconds(10));
        private static WaitTimer _smokeScreenTimer = new WaitTimer(TimeSpan.FromSeconds(10));
        private static WaitTimer _companionTimer = new WaitTimer(TimeSpan.FromSeconds(30));

        static void OnGameLeft(object sender, EventArgs e)
        {
            _markTimer.Stop();
            _smokeScreenTimer.Stop();
            _companionTimer.Stop();
        }

        public static bool SpamSmokeScreen = false;

        [Class(ActorClass.DemonHunter)]
        [Behavior(BehaviorType.Buff)]
        public static Composite DemonHunterBuffs()
        {
            return
                new PrioritySelector(
                    Common.CreateWaitForAttack(),

                    new Decorator(ret =>  _companionTimer.IsFinished && PowerManager.CanCast(SNOPower.DemonHunter_Companion),
                        new Sequence(
                            new SelfCast(SNOPower.DemonHunter_Companion, req => !HasCompanion),
                            new Action(ret => _companionTimer.Reset()))),

                    new Decorator(ret => (_smokeScreenTimer.IsFinished || SpamSmokeScreen) && PowerManager.CanCast(SNOPower.DemonHunter_SmokeScreen),
                        new Sequence(
                            new SelfCast(SNOPower.DemonHunter_SmokeScreen, extra => ZetaDia.Me.HitpointsCurrentPct <= 0.50),
                            new Action(ret => _smokeScreenTimer.Reset())))
                );
        }

        [Class(ActorClass.DemonHunter)]
        [Behavior(BehaviorType.Combat)]
        public static Composite DemonHunterCombat()
        {
            return
               new PrioritySelector(ctx => CombatTargeting.Instance.FirstNpc,

                    Common.CreateWaitWhileIncapacitated(),
                    Common.CreateWaitForAttack(),
                    Common.CreateUsePotion(),

                    new Decorator(ctx => ctx != null,
                       new PrioritySelector(
                            new Decorator(ctx => ctx != null && ((DiaUnit)ctx).Distance > 50f,
                                Movement.MoveTo(ctx => ((DiaUnit)ctx).Position, 15f)
                            ),


                            //These could use some better values, 0.50 = 50% 
                            new SelfCast(SNOPower.DemonHunter_ShadowPower, extra => ZetaDia.Me.HitpointsCurrentPct <= 0.50),

                            //Needs a rune check
                            new Decorator(ret => _smokeScreenTimer.IsFinished && PowerManager.CanCast(SNOPower.DemonHunter_SmokeScreen),
                                new Sequence(
                                    new SelfCast(SNOPower.DemonHunter_SmokeScreen, extra => ZetaDia.Me.HitpointsCurrentPct <= 0.50),
                                    new Action(ret => _smokeScreenTimer.Reset()))),

                            new Decorator(ret => _markTimer.IsFinished && PowerManager.CanCast(SNOPower.DemonHunter_MarkedForDeath),
                                new Sequence(
                                    new CastOnUnit(SNOPower.DemonHunter_MarkedForDeath, ctx => ((DiaUnit)ctx).ACDGuid, ctx => Common.IsElite((DiaUnit)ctx)),
                                    new Action(ret => _markTimer.Reset()))),


                            // AOE
                            new SelfCast(SNOPower.DemonHunter_RainOfVengeance,
                                extra => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 45f) >= 3
                            ),
                            new CastOnUnit(SNOPower.DemonHunter_Strafe,
                                ctx => ((DiaUnit)ctx).ACDGuid,
                                req => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 45f) >= 2
                            ),
                            new CastOnUnit(SNOPower.DemonHunter_Multishot,
                                ctx => ((DiaUnit)ctx).ACDGuid,
                                req => Clusters.GetClusterCount(((DiaUnit)req), CombatTargeting.Instance.LastObjects, ClusterType.Radius, 45f) >= 2
                            ),
                            new CastOnUnit(SNOPower.DemonHunter_Chakram,
                                ctx => ((DiaUnit)ctx).ACDGuid,
                                req => Clusters.GetClusterCount(((DiaUnit)req), CombatTargeting.Instance.LastObjects, ClusterType.Radius, 25f) >= 2
                            ),
                            new SelfCast(SNOPower.DemonHunter_Grenades,
                                req => Clusters.GetClusterCount(((DiaUnit)req), CombatTargeting.Instance.LastObjects, ClusterType.Radius, 25f) >= 2
                            ),
                            new CastOnUnit(SNOPower.DemonHunter_FanOfKnives,
                                ctx => ((DiaUnit)ctx).ACDGuid,
                                req => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 15f) >= 2
                            ),
                            new CastOnUnit(SNOPower.DemonHunter_ClusterArrow,
                                ctx => ((DiaUnit)ctx).ACDGuid,
                                req => Clusters.GetClusterCount(((DiaUnit)req), CombatTargeting.Instance.LastObjects, ClusterType.Radius, 15f) >= 2 || Common.IsElite((DiaUnit)req)
                            ),
                            new CastOnUnit(SNOPower.DemonHunter_Sentry,
                                ctx => ((DiaUnit)ctx).ACDGuid,
                                req => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 35f) >= 2 || Common.IsElite((DiaUnit)req)
                            ),

                            //Will spam this spell as we cant read the power values for DH
                            new SelfCast(SNOPower.DemonHunter_Preparation),

                            // Singles
                            new CastOnUnit(SNOPower.DemonHunter_Impale, ctx => ((DiaUnit)ctx).ACDGuid),
                            new CastOnUnit(SNOPower.DemonHunter_RapidFire, ctx => ((DiaUnit)ctx).ACDGuid),
                            new CastOnUnit(SNOPower.DemonHunter_ElementalArrow, ctx => ((DiaUnit)ctx).ACDGuid),

                            // Hatred Generators
                            new CastOnUnit(SNOPower.DemonHunter_BolaShot, ctx => ((DiaUnit)ctx).ACDGuid),
                            new CastOnUnit(SNOPower.DemonHunter_EvasiveFire, ctx => ((DiaUnit)ctx).ACDGuid),
                            new CastOnUnit(SNOPower.DemonHunter_HungeringArrow, ctx => ((DiaUnit)ctx).ACDGuid),
                            new CastOnUnit(SNOPower.DemonHunter_EntanglingShot, ctx => ((DiaUnit)ctx).ACDGuid)
                        )
                   ),

                   new Action(ret => RunStatus.Success)
                   );
        }

        public static bool HasCompanion
        {
            get
            {
                int dynId = ZetaDia.Me.CommonData.DynamicId;
                var companion = ZetaDia.Actors.GetActorsOfType<DiaUnit>().FirstOrDefault(u => u.Name.Contains("Companion") && u.SummonedByACDId == dynId);
                return companion != null && companion.CommonData != null;
            }
        }

        public static void DemonHunterOnLevelUp(object sender, EventArgs e)
        {
            if (ZetaDia.Me.ActorClass != ActorClass.DemonHunter)
                return;

            int myLevel = ZetaDia.Me.Level;

            Logger.Write("Player leveled up, congrats! Your level is now: {0}",
                myLevel
                );

            #region Primary Slot
            if (myLevel == 6)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_HungeringArrow, 1, 0);
                Logger.Write("Add [R] Puncturing Arrow to Hungering Arrow");
            }
            if (myLevel == 14)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_EvasiveFire, -1, 0);
                Logger.Write("Setting Evasive Fire as Primary skill");
            }
            if (myLevel == 21)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_EvasiveFire, 1, 0);
                Logger.Write("Setting [R] Shrapnel to Evasive Fire");
            }
            if (myLevel == 34)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_EvasiveFire, 3, 0);
                Logger.Write("Setting [R] Covering Fire to Evasive Fire");
            }
            #endregion

            #region Secondary Slot
            if (myLevel == 2)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_Impale, -1, 1);
                Logger.Write("Setting Impale as Secondary skill");
            }

            if (myLevel == 22)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_Multishot, -1, 1);
                Logger.Write("Setting Multishot as Secondary skill");
            }

            if (myLevel == 26)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_Multishot, 1, 1);
                Logger.Write("Setting [R] Fire at Will to Multishot");
            }
            #endregion

            #region Defensive Slot
            if (myLevel == 4)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_Caltrops, -1, 2);
                Logger.Write("Setting Caltrops as Defensive skill");
            }

            if (myLevel == 8)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_SmokeScreen, -1, 2);
                Logger.Write("Setting Smoke Screen as Defensive skill");
            }

            if (myLevel == 14)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_SmokeScreen, 1, 2);
                Logger.Write("Setting [R] Displacement to Smoke Screen");
            }

            if (myLevel == 33)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_SmokeScreen, 3, 2);
                Logger.Write("Setting [R] Breathe Deep to Smoke Screen");
            }
            #endregion

            #region Hunting Slot
            if (myLevel == 9)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_Vault, -1, 3);
                Logger.Write("Setting Vault as Hunting skill");
            }
            if (myLevel == 9)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_Companion, -1, 3);
                Logger.Write("Setting Companion as Hunting skill");
            }
            #endregion

            #region Device Slot
            if (myLevel == 21)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_MarkedForDeath, -1, 4);
                Logger.Write("Setting Marked for Death as Device skill");
            }
            if (myLevel == 27)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_MarkedForDeath, 1, 4);
                Logger.Write("Setting [R] Contagion to Marked for Death");
            }
            #endregion

            #region Archery Slot
            if (myLevel == 16)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.DemonHunter_ShadowPower, -1, 5);
                Logger.Write("Setting Shadow Power as Archery skill");
            }
            #endregion

        }
    }
}
